package handlers

import (
	"fmt"
	"net/http"

	"github.com/gin-gonic/gin"
	"github.com/sirupsen/logrus"
	"github.com/yourusername/virt-manager-go/internal/models"
	"github.com/yourusername/virt-manager-go/internal/service"
)

// ConnectionHandler handles connection management requests
type ConnectionHandler struct {
	connMgr *service.ConnectionManager
	log     *logrus.Logger
}

// NewConnectionHandler creates a new connection handler
func NewConnectionHandler(connMgr *service.ConnectionManager, log *logrus.Logger) *ConnectionHandler {
	return &ConnectionHandler{
		connMgr: connMgr,
		log:     log,
	}
}

// ListConnections returns all connections
//
//	@Summary		List connections
//	@Description	Returns all configured libvirt connections
//	@Tags			connections
//	@Accept			json
//	@Produce		json
//	@Success		200	{object}	map[string]interface{}	"{"connections": []models.ConnectionDetail, "count": int}"
//	@Failure		500	{object}	map[string]interface{}	"Internal Server Error"
//	@Router			/connections [get]
func (h *ConnectionHandler) ListConnections(c *gin.Context) {
	connections := h.connMgr.ListConnections()

	c.JSON(http.StatusOK, gin.H{
		"connections": connections,
		"count":       len(connections),
	})
}

// GetConnection returns a specific connection
//
//	@Summary		Get connection details
//	@Description	Returns detailed information about a specific connection
//	@Tags			connections
//	@Accept			json
//	@Produce		json
//	@Param			connection	query		string	true	"Connection ID"
//	@Success		200			{object}	models.ConnectionDetail
//	@Failure		404			{object}	map[string]interface{}	"Connection not found"
//	@Router			/connection [get]
func (h *ConnectionHandler) GetConnection(c *gin.Context) {
	name := c.Query("connection")
	if name == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "connection query parameter is required"})
		return
	}

	conn, err := h.connMgr.GetConnection(name)
	if err != nil {
		h.log.WithError(err).WithField("name", name).Error("Connection not found")
		c.JSON(http.StatusNotFound, gin.H{"error": "connection not found"})
		return
	}

	hostname, _ := conn.GetHostname()
	version, _ := conn.GetVersion()
	alive := conn.IsAlive()

	info := models.ConnectionDetail{
		Name:      name,
		URI:       conn.GetURI(),
		Connected: alive,
		Hostname:  hostname,
		Version:   version,
	}

	c.JSON(http.StatusOK, info)
}

// CreateConnection adds a new connection
//
//	@Summary		Create connection
//	@Description	Creates a new libvirt connection
//	@Tags			connections
//	@Accept			json
//	@Produce		json
//	@Param			connection	body		models.CreateConnectionRequest	true	"Connection configuration"
//	@Success		201			{object}	map[string]interface{}			"{"message": string, "name": string}"
//	@Failure		400			{object}	map[string]interface{}			"Bad Request"
//	@Failure		409			{object}	map[string]interface{}			"Conflict - Connection already exists"
//	@Failure		500			{object}	map[string]interface{}			"Internal Server Error"
//	@Router			/connections [post]
func (h *ConnectionHandler) CreateConnection(c *gin.Context) {
	var req models.CreateConnectionRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	// Validate request
	if req.Name == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "name is required"})
		return
	}
	if req.URI == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "uri is required"})
		return
	}

	// Check if connection already exists
	if h.connMgr.HasConnection(req.Name) {
		c.JSON(http.StatusConflict, gin.H{"error": "connection already exists"})
		return
	}

	// Add connection
	if err := h.connMgr.AddConnection(req.Name, req.URI); err != nil {
		h.log.WithError(err).Error("Failed to add connection")
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	// Set as default if requested
	if req.SetAsDefault {
		if err := h.connMgr.SetDefaultConnection(req.Name); err != nil {
			h.log.WithError(err).Warn("Failed to set as default connection")
		}
	}

	h.log.WithFields(logrus.Fields{
		"name": req.Name,
		"uri":  req.URI,
	}).Info("Connection created successfully")

	// 获取连接详情以返回给前端
	conn, err := h.connMgr.GetConnection(req.Name)
	if err != nil {
		h.log.WithError(err).Error("Failed to get newly created connection")
		c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to get connection details"})
		return
	}

	hostname, _ := conn.GetHostname()
	version, _ := conn.GetVersion()
	alive := conn.IsAlive()

	detail := models.ConnectionDetail{
		Name:      req.Name,
		URI:       conn.GetURI(),
		Connected: alive,
		Hostname:  hostname,
		Version:   version,
	}

	// 返回符合前端期望的数据结构
	response := gin.H{
		"data":    detail,
		"message": "connection created successfully",
	}

	c.JSON(http.StatusCreated, response)
}

// DeleteConnection removes a connection
//
//	@Summary		Delete connection
//	@Description	Removes a libvirt connection
//	@Tags			connections
//	@Accept			json
//	@Produce		json
//	@Param			connection	query		string					true	"Connection ID"
//	@Success		200			{object}	map[string]interface{}	"{"message": string}"
//	@Failure		404			{object}	map[string]interface{}	"Connection not found"
//	@Failure		500			{object}	map[string]interface{}	"Internal Server Error"
//	@Router			/connection [delete]
func (h *ConnectionHandler) DeleteConnection(c *gin.Context) {
	name := c.Query("connection")
	if name == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "connection query parameter is required"})
		return
	}

	if err := h.connMgr.RemoveConnection(name); err != nil {
		h.log.WithError(err).WithField("name", name).Error("Failed to remove connection")
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	h.log.WithField("name", name).Info("Connection deleted successfully")
	c.JSON(http.StatusOK, gin.H{"message": "connection deleted successfully"})
}

// SetDefaultConnection sets the default connection
//
//	@Summary		Set default connection
//	@Description	Sets a libvirt connection as the default connection
//	@Tags			connections
//	@Accept			json
//	@Produce		json
//	@Param			connection	query		string					true	"Connection ID"
//	@Success		200			{object}	map[string]interface{}	"{"message": string}"
//	@Failure		404			{object}	map[string]interface{}	"Connection not found"
//	@Failure		500			{object}	map[string]interface{}	"Internal Server Error"
//	@Router			/connection/set-default [post]
func (h *ConnectionHandler) SetDefaultConnection(c *gin.Context) {
	name := c.Query("connection")
	if name == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "connection query parameter is required"})
		return
	}

	if err := h.connMgr.SetDefaultConnection(name); err != nil {
		h.log.WithError(err).WithField("name", name).Error("Failed to set default connection")
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	h.log.WithField("name", name).Info("Default connection updated")
	c.JSON(http.StatusOK, gin.H{"message": "default connection updated"})
}

// ReconnectConnection attempts to reconnect a connection
//
//	@Summary		Reconnect connection
//	@Description	Attempts to reconnect to a libvirt connection
//	@Tags			connections
//	@Accept			json
//	@Produce		json
//	@Param			connection	query		string					true	"Connection ID"
//	@Success		200			{object}	map[string]interface{}	"{"message": string}"
//	@Failure		404			{object}	map[string]interface{}	"Connection not found"
//	@Failure		500			{object}	map[string]interface{}	"Internal Server Error"
//	@Router			/connection/reconnect [post]
func (h *ConnectionHandler) ReconnectConnection(c *gin.Context) {
	name := c.Query("connection")
	if name == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "connection query parameter is required"})
		return
	}

	conn, err := h.connMgr.GetConnection(name)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "connection not found"})
		return
	}

	if err := conn.Reconnect(); err != nil {
		h.log.WithError(err).WithField("name", name).Error("Reconnection failed")
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	h.log.WithField("name", name).Info("Reconnected successfully")
	c.JSON(http.StatusOK, gin.H{"message": "reconnected successfully"})
}

// ReconnectAll attempts to reconnect all disconnected connections
//
//	@Summary		Reconnect all connections
//	@Description	Attempts to reconnect all disconnected libvirt connections
//	@Tags			connections
//	@Accept			json
//	@Produce		json
//	@Success		200	{object}	map[string]interface{}	"{"message": string}"
//	@Failure		500	{object}	map[string]interface{}	"Internal Server Error"
//	@Router			/connections/reconnect-all [post]
func (h *ConnectionHandler) ReconnectAll(c *gin.Context) {
	if err := h.connMgr.ReconnectAll(); err != nil {
		h.log.WithError(err).Warn("Some connections failed to reconnect")
		c.JSON(http.StatusOK, gin.H{
			"message": "reconnection attempted with some errors",
			"error":   err.Error(),
		})
		return
	}

	h.log.Info("All connections reconnected successfully")
	c.JSON(http.StatusOK, gin.H{"message": "all connections reconnected successfully"})
}

// GetConnectionCapabilities returns connection capabilities
//
//	@Summary		Get connection capabilities
//	@Description	Returns XML capabilities document for a specific connection
//	@Tags			connections
//	@Accept			json
//	@Produce		xml
//	@Param			connection	query		string					true	"Connection ID"
//	@Success		200			{string}	string					"XML capabilities document"
//	@Failure		404			{object}	map[string]interface{}	"Connection not found"
//	@Failure		500			{object}	map[string]interface{}	"Internal Server Error"
//	@Router			/connection/capabilities [get]
func (h *ConnectionHandler) GetConnectionCapabilities(c *gin.Context) {
	name := c.Query("connection")
	if name == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "connection query parameter is required"})
		return
	}

	conn, err := h.connMgr.GetConnection(name)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "connection not found"})
		return
	}

	caps, err := conn.GetCapabilities()
	if err != nil {
		h.log.WithError(err).Error("Failed to get capabilities")
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.Data(http.StatusOK, "application/xml", []byte(caps))
}

// GetConnectionInfo returns detailed connection information
//
//	@Summary		Get connection info
//	@Description	Returns detailed information about a specific connection
//	@Tags			connections
//	@Accept			json
//	@Produce		json
//	@Param			connection	query		string					true	"Connection ID"
//	@Success		200			{object}	map[string]interface{}	"Connection information"
//	@Failure		404			{object}	map[string]interface{}	"Connection not found"
//	@Failure		500			{object}	map[string]interface{}	"Internal Server Error"
//	@Router			/connection/info [get]
func (h *ConnectionHandler) GetConnectionInfo(c *gin.Context) {
	name := c.Query("connection")
	if name == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "connection query parameter is required"})
		return
	}

	conn, err := h.connMgr.GetConnection(name)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "connection not found"})
		return
	}

	hostname, _ := conn.GetHostname()
	libvirtVersion, _ := conn.GetVersion()
	alive := conn.IsAlive()

	hvConn := conn.GetConnect()
	hvVersion, _ := hvConn.GetVersion()
	uri, _ := hvConn.GetURI()
	hvType, _ := hvConn.GetType()

	info := gin.H{
		"name":               name,
		"uri":                uri,
		"connected":          alive,
		"hostname":           hostname,
		"hypervisor_type":    hvType,
		"libvirt_version":    libvirtVersion,
		"hypervisor_version": hvVersion,
	}

	c.JSON(http.StatusOK, info)
}

// HealthCheck performs a health check on a specific connection
//
//	@Summary		Connection health check
//	@Description	Performs a health check on a specific libvirt connection
//	@Tags			connections
//	@Accept			json
//	@Produce		json
//	@Param			connection	query		string					true	"Connection ID"
//	@Success		200			{object}	map[string]interface{}	"{"status": string, "message": string}"
//	@Failure		404			{object}	map[string]interface{}	"Connection not found"
//	@Failure		500			{object}	map[string]interface{}	"Connection health check failed"
//	@Router			/connection/health [get]
func (h *ConnectionHandler) HealthCheck(c *gin.Context) {
	name := c.Query("connection")
	if name == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "connection query parameter is required"})
		return
	}

	conn, err := h.connMgr.GetConnection(name)
	if err != nil {
		c.JSON(http.StatusNotFound, gin.H{"error": "connection not found"})
		return
	}

	alive := conn.IsAlive()

	if alive {
		c.JSON(http.StatusOK, gin.H{
			"status":  "healthy",
			"message": "Connection is alive and functioning properly",
		})
	} else {
		c.JSON(http.StatusInternalServerError, gin.H{
			"status":  "unhealthy",
			"message": "Connection is not alive",
		})
	}
}

// CloseConnection closes a specific connection
//
//	@Summary		Close connection
//	@Description	Closes a specific libvirt connection
//	@Tags			connections
//	@Accept			json
//	@Produce		json
//	@Param			connection	query		string					true	"Connection ID"
//	@Success		200			{object}	map[string]interface{}	"{"message": string}"
//	@Failure		404			{object}	map[string]interface{}	"Connection not found"
//	@Failure		500			{object}	map[string]interface{}	"Internal Server Error"
//	@Router			/connection/close [post]
func (h *ConnectionHandler) CloseConnection(c *gin.Context) {
	name := c.Query("connection")
	if name == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "connection query parameter is required"})
		return
	}

	if err := h.connMgr.CloseConnection(name); err != nil {
		h.log.WithError(err).WithField("name", name).Error("Failed to close connection")
		if err.Error() == fmt.Sprintf("connection %s not found", name) {
			c.JSON(http.StatusNotFound, gin.H{"error": "connection not found"})
		} else {
			c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		}
		return
	}

	h.log.WithField("name", name).Info("Connection closed successfully")
	c.JSON(http.StatusOK, gin.H{"message": "connection closed successfully"})
}
